gskcairorendererprivate.h \
gskdebugprivate.h \
gskgldriverprivate.h \
+ gskglprofilerprivate.h \
gskglrendererprivate.h \
gskprivate.h \
gskrendererprivate.h \
gskcairorenderer.c \
gskdebug.c \
gskgldriver.c \
+ gskglprofiler.c \
gskglrenderer.c \
gskrenderer.c \
gskrendernode.c \
--- /dev/null
+#include "config.h"
+
+#include "gskglprofilerprivate.h"
+
+#include <epoxy/gl.h>
+
+#define N_QUERIES 4
+
+struct _GskGLProfiler
+{
+ GObject parent_instance;
+
+ /* Creating GL queries is kind of expensive, so we pay the
+ * price upfront and create a circular buffer of queries
+ */
+ GLuint gl_queries[N_QUERIES];
+ GLuint active_query;
+
+ gboolean has_timer : 1;
+ gboolean first_frame : 1;
+};
+
+G_DEFINE_TYPE (GskGLProfiler, gsk_gl_profiler, G_TYPE_OBJECT)
+
+static void
+gsk_gl_profiler_finalize (GObject *gobject)
+{
+ GskGLProfiler *self = GSK_GL_PROFILER (gobject);
+
+ glDeleteQueries (N_QUERIES, self->gl_queries);
+
+ G_OBJECT_CLASS (gsk_gl_profiler_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_gl_profiler_class_init (GskGLProfilerClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = gsk_gl_profiler_finalize;
+}
+
+static void
+gsk_gl_profiler_init (GskGLProfiler *self)
+{
+ glGenQueries (N_QUERIES, self->gl_queries);
+
+ self->first_frame = TRUE;
+ self->has_timer = epoxy_has_gl_extension ("GL_ARB_timer_query");
+}
+
+GskGLProfiler *
+gsk_gl_profiler_new (void)
+{
+ return g_object_new (GSK_TYPE_GL_PROFILER, NULL);
+}
+
+void
+gsk_gl_profiler_begin_gpu_region (GskGLProfiler *profiler)
+{
+ GLuint query_id;
+
+ g_return_if_fail (GSK_IS_GL_PROFILER (profiler));
+
+ if (!profiler->has_timer)
+ return;
+
+ query_id = profiler->gl_queries[profiler->active_query];
+ glBeginQuery (GL_TIME_ELAPSED, query_id);
+}
+
+guint64
+gsk_gl_profiler_end_gpu_region (GskGLProfiler *profiler)
+{
+ GLuint last_query_id;
+ GLint res;
+ GLuint64 elapsed;
+
+ g_return_val_if_fail (GSK_IS_GL_PROFILER (profiler), 0);
+
+ if (!profiler->has_timer)
+ return 0;
+
+ glEndQuery (GL_TIME_ELAPSED);
+
+ if (profiler->active_query == 0)
+ last_query_id = N_QUERIES - 1;
+ else
+ last_query_id = profiler->active_query - 1;
+
+ /* Advance iterator */
+ profiler->active_query += 1;
+ if (profiler->active_query == N_QUERIES)
+ profiler->active_query = 0;
+
+ /* If this is the first frame we already have a result */
+ if (profiler->first_frame)
+ {
+ profiler->first_frame = FALSE;
+ return 0;
+ }
+
+ glGetQueryObjectiv (profiler->gl_queries[last_query_id], GL_QUERY_RESULT_AVAILABLE, &res);
+ if (res == 1)
+ glGetQueryObjectui64v (profiler->gl_queries[last_query_id], GL_QUERY_RESULT, &elapsed);
+ else
+ elapsed = 0;
+
+ return elapsed;
+}
--- /dev/null
+#ifndef __GSK_GL_PROFILER_PRIVATE_H__
+#define __GSK_GL_PROFILER_PRIVATE_H__
+
+#include <gsk/gsktypes.h>
+
+G_BEGIN_DECLS
+
+#define GSK_TYPE_GL_PROFILER (gsk_gl_profiler_get_type ())
+G_DECLARE_FINAL_TYPE (GskGLProfiler, gsk_gl_profiler, GSK, GL_PROFILER, GObject)
+
+GskGLProfiler * gsk_gl_profiler_new (void);
+
+void gsk_gl_profiler_begin_gpu_region (GskGLProfiler *profiler);
+guint64 gsk_gl_profiler_end_gpu_region (GskGLProfiler *profiler);
+
+G_END_DECLS
+
+#endif /* __GSK_GL_PROFILER_PRIVATE_H__ */
#include "gskdebugprivate.h"
#include "gskenums.h"
#include "gskgldriverprivate.h"
+#include "gskglprofilerprivate.h"
#include "gskrendererprivate.h"
#include "gskrendernodeprivate.h"
#include "gskrendernodeiter.h"
GQuark attributes[N_ATTRIBUTES];
GskGLDriver *gl_driver;
-
+ GskGLProfiler *gl_profiler;
GskShaderBuilder *shader_builder;
int gl_min_filter;
g_assert (self->gl_driver == NULL);
self->gl_driver = gsk_gl_driver_new (self->context);
+ self->gl_profiler = gsk_gl_profiler_new ();
GSK_NOTE (OPENGL, g_print ("Creating buffers and programs\n"));
if (!gsk_gl_renderer_create_programs (self))
gsk_gl_renderer_destroy_buffers (self);
gsk_gl_renderer_destroy_programs (self);
+ g_clear_object (&self->gl_profiler);
g_clear_object (&self->gl_driver);
if (self->context == gdk_gl_context_get_current ())
gboolean use_alpha;
int status;
guint i;
+ guint64 gpu_time;
if (self->context == NULL)
return;
if (!gsk_gl_renderer_validate_tree (self, root))
goto out;
+ gsk_gl_profiler_begin_gpu_region (self->gl_profiler);
+
gsk_gl_driver_begin_frame (self->gl_driver);
/* Ensure that the viewport is up to date */
GSK_NOTE (OPENGL, g_print ("Drawing GL content on Cairo surface using a %s\n",
self->texture_id != 0 ? "texture" : "renderbuffer"));
+ gsk_gl_driver_end_frame (self->gl_driver);
+ gpu_time = gsk_gl_profiler_end_gpu_region (self->gl_profiler);
+ GSK_NOTE (OPENGL, g_print ("GPU time: %" G_GUINT64_FORMAT " nsec\n", gpu_time));
+
out:
use_alpha = gsk_renderer_get_use_alpha (renderer);
0, 0, viewport.size.width, viewport.size.height);
gdk_gl_context_make_current (self->context);
- gsk_gl_driver_end_frame (self->gl_driver);
gsk_gl_renderer_clear_tree (self);
}